package halma;

import java.util.ArrayList;
import java.util.Observable;

/*
 * HalmaBoard.java
 * 
 * Create a board, check move validity and perform move.
 * 
 */

public class HalmaBoard extends Observable implements Board {
	private int fieldWidth = 0;

	private int fieldHeight = 0;

	public Field field[][];

	private Field startField;

	// private Field targetField;
	// to store search path
	private ArrayList<Field> visitedOccFields = new ArrayList();

	private ArrayList<Field> visitedFreeFields = new ArrayList();

	private ArrayList<Field> validFreeFields = new ArrayList();

	// the last valid jumppoint, needed by multi jumps
	private Field lastValidFreeField = new Field(-1, -1, -1);

	private int boardType;

	// Constructors
	public HalmaBoard() {
		boardType = HalmaSettings.BOARD_STARLIKE;
		fieldHeight = 36;
		fieldWidth = 25;
		field = new Field[fieldHeight][fieldWidth];
	}

	public HalmaBoard(int boardType) {
		this.boardType = boardType;
		fieldHeight = 36;
		fieldWidth = 25;
		field = new Field[fieldHeight][fieldWidth];
	}

	// Getters and Setters
	public int getWidth() {
		return fieldWidth;
	}

	public int getHeight() {
		return fieldHeight;
	}

	public Field getField(int x, int y) {
		return field[x][y];
	}

	public void setField(int x, int y, Field field) {
		this.field[x][y] = field;
	}

	public Field[][] getField() {
		return field;
	}

	/*
	 * void createInitialField() Define the board as a two-dimensional array (n *
	 * n) Field types are declared in HalmaSettings.
	 */
	public void createInitialField() {
		switch (this.boardType) {
		case HalmaSettings.BOARD_QUADRATICALLY:
			break;

		case HalmaSettings.BOARD_STARLIKE:
			// black out everything
			for (int i = 0; i < fieldHeight; i++) {
				for (int j = 0; j < fieldWidth; j++) {
					// field[i][j]=-1;
					field[i][j] = new Field(-1, 0, 0, i, j);
				}
			}
			// field
			int center = 13;
			for (int i = 10; i < 18; i++) {
				for (int j = center - ((i - 4) / 2); j < center + ((i - 2) / 2); j++) {
					field[i][j - 1] = new Field(0, 0, 0);
					field[34 - i][j - 1] = new Field(0, 0, 0);
					j++;
				}
				i++;
			}

			// players
			center = 13;
			for (int i = 0; i < 12; i++) {
				for (int j = center - (i / 2); j < center + (i / 2); j++) {
					// check for start- and end base
					switch (HalmaSettings.NUMBER_OF_PLAYERS) {
					case 2:
						field[i - 2][j] = new Field(0, 0, 0);
						field[36 - i][j] = new Field(0, 0, 0);
						j++;
						break;
					case 3:
						field[i - 2][j] = new Field(1, 1, 0);
						field[36 - i][j] = new Field(0, 0, 1);
						j++;
						break;
					case 4:
						field[i - 2][j] = new Field(0, 0, 0);
						field[36 - i][j] = new Field(0, 0, 0);
						j++;
						break;
					case 6:
						field[i - 2][j] = new Field(1, 1, 4);
						field[36 - i][j] = new Field(4, 4, 1);
						j++;
						break;
					}

				}
				i++;
			}
			center = 5;
			for (int i = 8; i < 20; i++) {
				for (int j = center - ((i - 8) / 2); j < center + ((i - 8) / 2); j++) {

					switch (HalmaSettings.NUMBER_OF_PLAYERS) {
					case 2:
						field[26 - i][j + 16] = new Field(2, 2, 0);
						field[i + 8][j] = new Field(0, 0, 2);
						field[26 - i][j] = new Field(1, 1, 0);
						field[i + 8][j + 16] = new Field(0, 0, 1);
						j++;
						break;
					case 3:
						field[26 - i][j + 16] = new Field(3, 3, 0);
						field[i + 8][j] = new Field(0, 0, 3);
						field[26 - i][j] = new Field(2, 2, 0);
						field[i + 8][j + 16] = new Field(0, 0, 2);
						j++;
						break;
					case 4:
						field[26 - i][j + 16] = new Field(2, 2, 3);
						field[i + 8][j] = new Field(3, 3, 2);
						field[26 - i][j] = new Field(1, 1, 4);
						field[i + 8][j + 16] = new Field(4, 4, 1);
						j++;
						break;
					case 6:
						field[26 - i][j + 16] = new Field(2, 2, 5);
						field[i + 8][j] = new Field(5, 5, 2);
						field[26 - i][j] = new Field(6, 6, 3);
						field[i + 8][j + 16] = new Field(3, 3, 6);
						j++;
						break;
					}
				}
				i++;
			}

			for (int i = 0; i < 26; i++) {
				for (int j = 8; j < 18; j++) {
					field[8][j] = new Field(0, 0, 0);
					field[26][j] = new Field(0, 0, 0);
					j++;
				}
				i++;
			}
			field[10][7] = new Field(0, 0, 0);
			field[10][17] = new Field(0, 0, 0);
			field[12][6] = new Field(0, 0, 0);
			field[12][18] = new Field(0, 0, 0);
			field[14][5] = new Field(0, 0, 0);
			field[14][19] = new Field(0, 0, 0);
			field[16][4] = new Field(0, 0, 0);
			field[16][20] = new Field(0, 0, 0);
			field[18][4] = new Field(0, 0, 0);
			field[18][20] = new Field(0, 0, 0);
			field[24][7] = new Field(0, 0, 0);
			field[24][17] = new Field(0, 0, 0);
			field[22][6] = new Field(0, 0, 0);
			field[22][18] = new Field(0, 0, 0);
			field[20][5] = new Field(0, 0, 0);
			field[20][19] = new Field(0, 0, 0);
			for (int i = 18; i < 36; i++) {
				for (int j = 0; j < 25; j++) {
					field[i - 2][j] = field[i][j];
				}
				i++;
			}
			field[34][12] = new Field(-1, 0, 0);
			break;
		}

		// set field positions
		for (int i = 0; i < this.field.length; i++) {
			for (int j = 0; j < this.field[i].length; j++) {
				field[i][j].setXPosition(i);
				field[i][j].setYPosition(j);
			}
		}

		// now, notify observer
		setChanged();
		notifyObservers(this);
	}

	// perform move
	public void move(Player currentPlayer, Move move) {

		HalmaMove halmaMove = (HalmaMove) move;
		Field tmp = this.getField(halmaMove.getFromXPosition(), halmaMove
				.getFromYPosition());

		tmp.setFieldType(0);
		this.setField(halmaMove.getFromXPosition(), halmaMove
				.getFromYPosition(), tmp);
		tmp = this.getField(halmaMove.getToXPosition(), halmaMove
				.getToYPosition());
		tmp.setFieldType(currentPlayer.getId() + 1);
		this.setField(halmaMove.getToXPosition(), halmaMove.getToYPosition(),
				tmp);

		setChanged();
		notifyObservers(this);
	}

	// debug. print current board array
	public void showField() {
		for (int i = 0; i < field.length; i++) {
			for (int j = 0; j < field[i].length; j++) {
				if (field[i][j].getFieldType() != -1)
					System.out.print(" " + field[i][j].getFieldType());
				else
					System.out.print("  ");
			}
			System.out.println();
		}
	}

	/*
	 * boolean isMoveValid(Move move, Player player)
	 * 
	 * Checks recursively if a move is conform to Halma rules. If method returns
	 * false, the player has to enter his move again.
	 */
	public boolean isMoveValid(Move move, Player player) {
		HalmaMove halmaMove = (HalmaMove) move;

		int fieldFromY = halmaMove.getFromYPosition();
		int fieldFromX = halmaMove.getFromXPosition();
		int fieldToY = halmaMove.getToYPosition();
		int fieldToX = halmaMove.getToXPosition();

		startField = field[fieldFromX][fieldFromY];

		// define targetField
		Field targetField = field[fieldToX][fieldToY];

		/*
		 * System.out.println("isMoveValid: fieldType=" +
		 * field[fieldFromX][fieldFromY].getFieldType() + "->" +
		 * field[fieldToX][fieldToY].getFieldType());
		 */

		// was own token moved? FieldInfo == PlayerId +1 (playerIds are
		// starting width 0)
		if (player.getId() + 1 != field[fieldFromX][fieldFromY].getFieldType())
			return false;

		int targetFieldInfo = field[fieldToX][fieldToY].getFieldType();

		// Field free?
		if (targetFieldInfo != 0)
			return false;

		// Get neighbors of target field
		ArrayList<Field> neighbors = getNeighborList(targetField);

		boolean isSingleMove = false;

		// Move to a surrounding field?
		/*
		 * Iterating over neighbors to check, if start position is reached. If
		 * true, it's a single move to a surrounding field
		 */
		for (int i = 0; i < neighbors.size(); i++) {

			Field field = neighbors.get(i);

			// Field occupied?
			if (field.getFieldType() != HalmaSettings.NO_FIELD) {

				// Start position?
				if (field.getXPosition() == fieldFromX
						&& field.getYPosition() == fieldFromY) {
					isSingleMove = true;
					// return(true);
				}
			}
		}

		/*
		 * No move to neighbor field? Then it has to be a jump or the move is
		 * not valid.
		 */
		if (!isSingleMove) {
			/*
			 * Recursive search for a valid jump
			 */
			if (checkJump(startField, targetField))
				return (true);
			else
				return (false);
		} else if (targetFieldInfo > 0) {
			return (false);
		} else if (targetFieldInfo == HalmaSettings.NO_FIELD)
			return (false);

		return true;
	}

	private boolean checkJump(Field startField, Field targetField) {

		// SingleJump?
		// getNeighbors
		ArrayList<Field> neighbors = getNeighborList(startField);
		// Filter for occupiedFields
		ArrayList<Field> occFields = getOccupiedFields(neighbors);

		for (int i = 0; i < occFields.size(); i++) {
			Field occ = occFields.get(i);
			ArrayList<Field> neighbor2 = getNeighborList(occ);
			ArrayList<Field> frees = getFreeFields(neighbor2);

			for (int j = 0; j < frees.size(); j++) {
				Field free = frees.get(j);

				/*
				 * Target found? check direction, if not valid, whole validation
				 * returns false
				 */
				if (free.getXPosition() == targetField.getXPosition()
						&& free.getYPosition() == targetField.getYPosition()) {

					if (!isDirectionValid(startField, free)) {
						return false;
					} else {
						return true;
					}
				}
			}

		}

		// Target not found? -> MultipleJump?
		// return isMultipleJump(startField,targetField);
		return validateJump(this, startField.getXPosition(), startField
				.getYPosition(), targetField.getXPosition(), targetField
				.getYPosition());
	}

	ArrayList<Field> path = new ArrayList();

	public boolean validateJump(HalmaBoard board, int startX, int startY,
			int targetX, int targetY) {
		Field startField = board.field[startX][startY];

		boolean valid = false;

		ArrayList<Field> neighbors = getNeighborList(startField);
		ArrayList<Field> occFields = getOccupiedFields(neighbors);
		for (int i = 0; i < occFields.size(); i++) {
			Field field = occFields.get(i);
			valid = validateJumpRE(field.getXPosition(), field.getYPosition(),
					targetX, targetY, field.getXPosition(), field
							.getYPosition());
			// don't reuse path at next move
			path.clear();
			if (valid) {
				for (int j = 0; j < path.size(); j++) {

					Field field2 = path.get(j);
					System.out.println("Path: " + field2.getXPosition() + ", "
							+ field2.getYPosition());
					System.out.println("Type: " + field2.getFieldType());

				}
				return valid;
			} else {
				continue;
			}

		}
		// don't reuse path at next move
		path.clear();
		return valid;

	}

	public boolean validateJumpRE(int i, int j, int x, int y, int oldi, int oldj) {

		Field currentField = field[i][j];
		String status = getFieldState(currentField);

		// field visited and no seperator field? -> "legal" recursion?
		if (isFieldVisited(path, currentField)
				&& currentField.getXPosition() != -10) {
			return !checkLoop();
		}

		// Target found!
		if (i == x && j == y) {
			// Flush old coordinates
			oldi = 0;
			oldj = 0;
			// check last free field to check correct direction
			if (getLastFreeField(path) != null) {
				if (isDirectionValid(getLastFreeField(path), currentField)) {
					return true;
				}
			} else {
				return true;
			}

		}

		// horizontal search forward ignoring last checked field
		if (j < this.getWidth() - 2 && !(j + 2 == oldj)
				&& !getFieldState(field[i][j + 2]).equals("invalid"))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j + 2 && startField
					.getXPosition() == i))

				// Alternating field state?
				if (!getFieldState(field[i][j + 2]).equals(status)) {
					Field field2 = field[i][j];

					if (!getFieldState(field[i][j + 2]).equals("occupied")) {

						// Valid Direction?
						if (path.size() > 0 && getLastFreeField(path) != null) {
							if ((isDirectionValid(getLastFreeField(path),
									field[i][j + 2]))) {
								path.add(field2);
								if (validateJumpRE(i, j + 2, x, y, i, j))
									return true;
							}

						} else if ((isDirectionValid(startField,
								field[i][j + 2]))) {
							path.add(field2);
							if (validateJumpRE(i, j + 2, x, y, i, j))
								return true;
						}

					} else {
						path.add(field2);
						if (validateJumpRE(i, j + 2, x, y, i, j))
							return true;
					}
				}

		// horizontal search backward
		if (j > 2 && !(j - 2 == oldj))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j - 2 && startField
					.getXPosition() == i))
				// Alternating field state?
				if (!getFieldState(field[i][j - 2]).equals(status)
						&& !getFieldState(field[i][j - 2]).equals("invalid")) {
					Field field2 = field[i][j];

					if (!getFieldState(field[i][j -2]).equals("occupied")) {
						// Valid Direction?
						if (path.size() > 0 && getLastFreeField(path) != null) {
							if ((isDirectionValid(getLastFreeField(path),
									field[i][j - 2]))) {
								path.add(field2);
								if (validateJumpRE(i, j - 2, x, y, i, j))
									return true;
							}
						} else if (isDirectionValid(startField, field[i][j - 2])) {
							path.add(field2);
							if (validateJumpRE(i, j - 2, x, y, i, j))
								return true;
						}
					} else {
						path.add(field2);
						if (validateJumpRE(i, j - 2, x, y, i, j))
							return true;
					}

				}

		// positive diagonal search forward
		if (i < this.getHeight() - 2 && i > 0 && j > 0
				&& j < this.getWidth() - 1
				&& (!(i - 2 == oldi) || !(j + 1 == oldj)))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j + 1 && startField
					.getXPosition() == i - 2))
				// Alternating field state?
				if (!getFieldState(field[i - 2][j + 1]).equals(status)
						&& !getFieldState(field[i - 2][j + 1])
								.equals("invalid")) {
					Field field2 = field[i][j];

					// Valid Direction?
					if (!getFieldState(field[i - 2][j + 1]).equals("occupied")) {
						if (path.size() > 0 && getLastFreeField(path) != null) {

							if ((isDirectionValid(getLastFreeField(path),
									field[i - 2][j + 1]))) {
								path.add(field2);
								if (validateJumpRE(i - 2, j + 1, x, y, i, j)) {
									return true;
								}
							}
						} else if ((isDirectionValid(startField,
								field[i - 2][j + 1]))) {
							path.add(field2);
							if (validateJumpRE(i - 2, j + 1, x, y, i, j)) {
								return true;
							}
						}

					} else {
						path.add(field2);
						if (validateJumpRE(i - 2, j + 1, x, y, i, j)) {
							return true;
						}
					}
				}

		// positive diagonal search backward
		if (i < this.getHeight() - 2 && i > 0 && j < this.getWidth() - 1
				&& j > 0 && (!(i + 2 == oldi) || !(j - 1 == oldj)))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j - 1 && startField
					.getXPosition() == i + 2))

				// Alternating field state?
				if (!getFieldState(field[i + 2][j - 1]).equals(status)
						&& !getFieldState(field[i + 2][j - 1])
								.equals("invalid")) {
					Field field2 = field[i][j];

					if (!getFieldState(field[i + 2][j - 1]).equals("occupied")) {

						// Valid Direction?
						if (path.size() > 0 && getLastFreeField(path) != null) {

							if (isDirectionValid(getLastFreeField(path),
									field[i + 2][j - 1])) {
								path.add(field2);
								if (validateJumpRE(i + 2, j - 1, x, y, i, j)) {
									return true;
								}
							}
						} else if (isDirectionValid(startField,
								field[i + 2][j - 1])) {
							path.add(field2);
							if (validateJumpRE(i + 2, j - 1, x, y, i, j)) {
								return true;
							}
						}

					} else {
						path.add(field2);
						if (validateJumpRE(i + 2, j - 1, x, y, i, j)) {
							return true;
						}
					}
				}

		// negative diagonal search forward
		if (i < this.getHeight() - 2 && i > 0 && j > 0
				&& j < this.getWidth() - 1
				&& (!(i - 2 == oldi) || !(j - 1 == oldj)))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j - 1 && startField
					.getXPosition() == i - 2))

				// Alternating field state?
				if (!getFieldState(field[i - 2][j - 1]).equals(status)
						&& !getFieldState(field[i - 2][j - 1])
								.equals("invalid")) {
					Field field2 = field[i][j];

					if(!getFieldState(field[i - 2][j - 1]).equals(
					"occupied")){
						
						// Valid Direction?
						if (path.size() > 0
								&& getLastFreeField(path) != null) {
							if (isDirectionValid(getLastFreeField(path),
									field[i - 2][j - 1])) {
								path.add(field2);
								if (validateJumpRE(i - 2, j - 1, x, y, i, j)) {
									return true;
								}
							}

						} else if(isDirectionValid(startField,
								field[i - 2][j - 1])){
							path.add(field2);
							if (validateJumpRE(i - 2, j - 1, x, y, i, j)) {
								return true;
							}
						}	
					}else {
						path.add(field2);
						if (validateJumpRE(i - 2, j - 1, x, y, i, j)) {
							return true;
						}
					}

				}

		// negativ diagonal search backward
		if (i < this.getHeight() - 2 && i > 0 && j < this.getWidth() - 1
				&& j > 0 && (!(i + 2 == oldi) || !(j + 1 == oldj)))
			// dont't jump over startfield
			if (!(startField.getYPosition() == j + 1 && startField
					.getXPosition() == i + 2))

				// Alternating field state?
				if (!getFieldState(field[i + 2][j + 1]).equals(status)
						&& !getFieldState(field[i + 2][j + 1])
								.equals("invalid")) {
					Field field2 = field[i][j];

					if(!getFieldState(field[i + 2][j + 1]).equals(
					"occupied")){
				
						// Valid direction?
						// validation just works from one free field to another
						if (path.size() > 0
								&& getLastFreeField(path) != null) {

							if (isDirectionValid(getLastFreeField(path),
									field[i + 2][j + 1])) {
								path.add(field2);
								if (validateJumpRE(i + 2, j + 1, x, y, i, j)) {
									return true;
								}
							}

						} else if(isDirectionValid(startField,
								field[i + 2][j + 1])){
							path.add(field2);
							if (validateJumpRE(i + 2, j + 1, x, y, i, j)) {
								return true;
							}
						}	
						
						
					}else {
						path.add(field2);
						if (validateJumpRE(i + 2, j + 1, x, y, i, j)) {
							return true;
						}
					}
				}

		// Add seperator field to mark end of jump sequence
		path.add(new Field(-10, -10, -10, -10, -10));
		return false;
	}

	private Field getLastFreeField(ArrayList<Field> path) {
		Field field = new Field();
		if (path.size() > 0) {
			for (int i = path.size() - 1; i >= 0; i--) {
				field = path.get(i);
				if (getFieldState(field).equals("free")) {
					return field;
				}
			}

		} else {
			return null;
		}
		return null;
	}

	// Search for loop condition
	private boolean checkLoop() {
		// get last jump sequence from last seperator to next backward
		ArrayList<Field> subPathBackward = extractSubPathBackward(path);

		ArrayList<Field> tempPath = path;
		// remove all up to last seperator Field
		for (int k = tempPath.size() - 1; k >= 0; k--) {
			if (tempPath.get(k).getXPosition() == -10) {
				tempPath.remove(k);
			}
		}

		// remove seperator field
		if (tempPath.get(tempPath.size() - 1).getXPosition() == -10)
			tempPath.remove(tempPath.size() - 1);

		// remove last SubPath to get the next
		for (int k = subPathBackward.size() - 1; k >= 0; k--) {
			tempPath.remove(tempPath.size() - 1);
		}

		ArrayList<Field> nextSubPath = extractSubPathBackward(tempPath);

		// same SubPath? -> recursion
		if (subPathBackward.equals(nextSubPath)) {
			return true;
		} else {
			return false;
		}
	}

	/* Gets Subsquence from one seperator Field (x=-10) to next backward */
	private static ArrayList<Field> extractSubPathBackward(ArrayList<Field> path) {

		ArrayList<Field> subPath = new ArrayList();

		// get subpath
		// search for identical number sequences
		for (int i = path.size() - 1; i >= 0; i--) {
			// Path section from last seperator to next seperator, to get jump
			// sequence
			if (path.get(i).getXPosition() == -10) {
				for (int j = i - 1; j >= 0; j--) {
					if (path.get(j).getXPosition() != -10 && j >= 1) {
						subPath.add(path.get(j));
					} else {
						return revertPath(subPath);
					}
				}

			}
		}

		return revertPath(subPath);
	}

	// Reverting ArrayList
	public static ArrayList<Field> revertPath(ArrayList<Field> path) {

		ArrayList<Field> revertedPath = new ArrayList();

		for (int i = path.size() - 1; i >= 0; i--) {
			revertedPath.add(path.get(i));
		}

		return revertedPath;
	}

	// Field visited?
	private boolean isFieldVisited(ArrayList<Field> fieldList, Field field) {
		for (int i = 0; i < fieldList.size(); i++) {
			Field oldField = fieldList.get(i);
			if (oldField.getXPosition() == field.getXPosition()
					&& oldField.getYPosition() == field.getYPosition()) {
				return true;
			}
		}
		return false;
	}

	// TODO
	private static String getFieldState(Field field) {
		String status = "";
		if (field.getFieldType() > 0) {
			status = "occupied";
		} else if (field.getFieldType() == 0) {
			status = "free";
		} else {
			status = "invalid";
		}
		return status;
	}

	/* Filter all occupied fields from an list of fields */
	private ArrayList<Field> getOccupiedFields(ArrayList<Field> fieldList) {
		ArrayList<Field> occupiedFields = new ArrayList<Field>();

		for (int i = 0; i < fieldList.size(); i++) {
			Field field = fieldList.get(i);

			if (field.getFieldType() > 0) {
				occupiedFields.add(field);
			}
		}
		return occupiedFields;
	}

	/* Filter all free fields from an list of fields */
	private ArrayList<Field> getFreeFields(ArrayList<Field> fieldList) {
		ArrayList<Field> freeFields = new ArrayList<Field>();

		for (int i = 0; i < fieldList.size(); i++) {
			Field field = fieldList.get(i);

			if (field.getFieldType() == HalmaSettings.EMPTY_FIELD) {
				freeFields.add(field);
			}
		}
		return freeFields;
	}

	/*
	 * Get the surrounding fields of a defined field excluding the field itself,
	 * just valid fields are added, no dummy fields
	 * 
	 * Just in case of a field at the edge of board, dummy fields are created to
	 * avoid errors
	 */
	private ArrayList<Field> getNeighborList(Field field) {
		ArrayList<Field> neighborList = new ArrayList<Field>();

		// Get the Board
		Field[][] fields = getField();

		int x = field.getXPosition();
		int y = field.getYPosition();

		for (int i = x - 2; i <= x + 2; i++) {
			for (int j = y - 2; j <= y + 2; j++) {
				Field neighborField = new Field();

				// Field within board range?
				if (i >= 0 && j >= 0 && i < (fields.length)
						&& j < (fields[i].length)) {
					Field arrField = fields[i][j];

					// no dummy field? (fieldType != -1)
					if (arrField.getFieldType() != HalmaSettings.NO_FIELD) {

						// The targetField itself is not part of the
						// neighborhood

						if ((arrField.getXPosition() != field.getXPosition())
								|| (arrField.getYPosition() != field
										.getYPosition())) {

							neighborField = arrField;
							neighborList.add(arrField);
						}

					}
				} else {// create dummy fields (Fields out of board range)
					neighborField.setFieldType(HalmaSettings.NO_FIELD);
					neighborField.setHomeBaseFromPlayer(0);
					neighborField.setEndBaseFromPlayer(0);
					neighborField.setXPosition(HalmaSettings.DUMMY_POSITION);
					neighborField.setYPosition(HalmaSettings.DUMMY_POSITION);
				}

			}
		}

		return neighborList;
	}

	/***************************************************************************
	 * checks, if the moving direction is conform to the halma rules: a correct
	 * move has to be on a line without changes of direction whithin one single
	 * move.
	 * 
	 * it validates just the relation between a target field and the last free
	 * field
	 * 
	 * 
	 * @param startField,
	 *            targetField x-y-cooridnate pairs of start field and target
	 *            field
	 * @return boolean returns true, if diratcion is valid
	 * 
	 **************************************************************************/

	private boolean isDirectionValid(Field startField, Field targetField) {

		int startX = startField.getXPosition();
		int startY = startField.getYPosition();
		int targetX = targetField.getXPosition();
		int targetY = targetField.getYPosition();

		if ((startX == targetX - 4) && (startY == targetY - 2)) {
			return true;
		} else if ((startX == targetX - 4) && (startY == targetY + 2)) {
			return true;
		} else if ((startX == targetX) && (startY == targetY + 4)) {
			return true;
		} else if ((startX == targetX) && (startY == targetY - 4)) {
			return true;
		} else if ((startX == targetX + 4) && (startY == targetY + 2)) {
			return true;
		} else if ((startX == targetX + 4) && (startY == targetY - 2)) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * checks if Jump Direction in general is conform to halma rules
	 * 
	 * it proves if two fields are on a valid line (horizontal, vertical, both
	 * diagonals) the interval between both fields is not relevant
	 */
	private boolean isJumpDirectionValid(Field startField, Field targetField) {

		int startX = startField.getXPosition();
		int startY = startField.getYPosition();
		int targetX = targetField.getXPosition();
		int targetY = targetField.getYPosition();

		if (checkPositiveDiagonal(startField, targetField)) {
			return true;
		} else if (checkNegativeDiagonal(startField, targetField)) {
			return true;
		} else if ((startX == targetX)) {
			return true;
		} else if ((startX == targetX) && (startY == targetY)) {
			return true;
		} else {
			return false;
		}

	}

	// Checks if a field is on an increasing diagonal line to another field
	public boolean checkPositiveDiagonal(Field startField, Field targetField) {

		int startX = startField.getXPosition();
		int startY = startField.getYPosition();
		int targetX = targetField.getXPosition();
		int targetY = targetField.getYPosition();

		int diff = startX - targetX;
		int yValue = 0;
		if (diff % 2 == 0) {
			// Betrag bilden und halbieren
			yValue = Math.abs(diff) / 2;
			if (targetY == (Math.abs(yValue) + startY)) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	// Checks if a field is on a decreasing diagonal line to another field
	public boolean checkNegativeDiagonal(Field startField, Field targetField) {

		int startX = startField.getXPosition();
		int startY = startField.getYPosition();
		int targetX = targetField.getXPosition();
		int targetY = targetField.getYPosition();

		int diff = startX - targetX;
		int yValue = 0;
		if (diff % 2 == 0) {
			yValue = diff / 2;
			if (targetY == Math.abs(diff + (yValue))) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

}
